package com.fuego.creditsystemcommodity.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fuego.creditsystemcommodity.mapper.GoodMapper;
import com.fuego.creditsystemcommodity.service.IGoodInfoService;
import com.fuego.creditsystemcommodity.service.IGoodService;
import com.fuego.creditsystemuser.service.impl.UserServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import org.example.dto.Result;
import org.example.entity.Good;
import org.example.entity.GoodInfo;
import org.example.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static org.example.utils.RedisConstants.GOOD_INFO_STOCK_KEY;


@Service
public class GoodServiceImpl extends ServiceImpl<GoodMapper, Good> implements IGoodService {


    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private IGoodInfoService goodInfoService;
    @Autowired
    private UserServiceImpl userServiceImpl;

    @Override
    public Result queryGoodOfShop(Long shopId) {
        // 查询优惠券信息
        List<Good> goods = getBaseMapper().queryGoodOfShop(shopId);
        // 返回结果
        return Result.ok(goods);
    }

    @Override
    public Result queryGoodById(Long goodId) {

        List<Good> goods = getBaseMapper().queryGoodById(goodId);
        for (Good good : goods) {
            stringRedisTemplate.opsForValue().set(GOOD_INFO_STOCK_KEY+good.getId(),good.getStock().toString());
        }

        // 返回结果
        return Result.ok(goods);
    }

    @Override
    @Transactional
    public void addGoodInfo(GoodInfo goodInfo) {

        goodInfoService.save(goodInfo);
        //保存秒杀库存到redis中
        stringRedisTemplate.opsForValue().set(GOOD_INFO_STOCK_KEY+goodInfo.getGoodId(),goodInfo.getStock().toString());
    }

    @Override
    public Result queryAllGood() {
        List<Good> goods = getBaseMapper().queryAllGood();
        // 返回结果
        return Result.ok(goods);
    }

    public Result searchGood(String goodName){
        List<Good> goods = getBaseMapper().searchGood(goodName);

        return Result.ok(goods);
    }

    /**
     * 随机推荐商品
     * @param size 推荐商品的数量
     * @return 推荐的商品信息列表
     */
    private List<Good> randomRecommend(Integer size) {
        return getBaseMapper().randomRecommend(size);
    }

    /**
     * 推荐商品
     * @param size 推荐商品的数量
     * @param uid 针对用户id为uid的用户进行推荐
     * @return 推荐的商品信息列表
     */
    private List<Good> recommendGoods(Integer size, Long uid) {
        String redis_key = "py_recommendation:user_" + uid;

        // 这里需要访问redis，取出来的应该是一个json文本
        String recommendation_json = stringRedisTemplate.opsForValue().get(redis_key);

        List<Good> recommendation_goods = null;

        if (recommendation_json == null) {
            // 随机推荐size个
            recommendation_goods = this.randomRecommend(size);

        } else {
            // 推荐recommendation_goods的前size个
            // 之后，将推荐的recommendation_goods从缓存中删除

            List<Long> recommendationGoodsIdList = null;

            try {
                ObjectMapper objectMapper = new ObjectMapper();
                recommendationGoodsIdList = objectMapper.readValue(
                        recommendation_json,
                        new TypeReference<List<Long>>() {}
                );

            } catch (Exception e) {
                System.out.println("json解析异常。");
            }

            if (recommendationGoodsIdList == null) {
                // 随机推荐size个
                recommendation_goods = this.randomRecommend(size);
            } else if (recommendationGoodsIdList.size() <= size) {
                // 当推荐的商品不足或刚好size个
                // 不足的部分用随机推荐补足
                // 销毁redis中对应的键值对

                recommendation_goods = getBaseMapper().queryGoodByIds(recommendationGoodsIdList);

                List<Good> randomPart = this.randomRecommend(size - recommendation_goods.size());

                recommendation_goods.addAll(randomPart);

                // 下面销毁redis中对应的键值对
                stringRedisTemplate.delete(redis_key);

            } else {
                // 取前size个商品正常推荐
                // 随后在redis缓存中销毁推荐的商品
                // 用户不希望看到重复的推荐

                List<Long> remainingIds = recommendationGoodsIdList.subList(size, recommendationGoodsIdList.size());
                recommendationGoodsIdList = recommendationGoodsIdList.subList(0, size);

                recommendation_goods = getBaseMapper().queryGoodByIds(recommendationGoodsIdList);

                List<Good> randomPart = this.randomRecommend(size - recommendation_goods.size());

                recommendation_goods.addAll(randomPart);

                // 下面将remainingIds编码为json上传到redis
                try {
                    String remainingIdsJson = new ObjectMapper().writeValueAsString(remainingIds);
                    stringRedisTemplate.opsForValue().set(redis_key, remainingIdsJson);
                } catch (Exception e) {
                    System.out.println("json序列化异常。");
                }

            }
        }

        return recommendation_goods;
    }

    /**
     * 分页展示商品。
     * 这里同时需要实现商品的推荐功能，在redis中取pageSize长度的商品进行推荐。
     * 如果没有可取的，随机推荐以补足。
     * @param page 当前页
     * @param pageSize 每页条数
     * @return 需要当前页的商品数据和总商品数
     */
    public Result pageGood(Integer page, Integer pageSize, HttpServletRequest request) {
        // TODO
        // 潜在异常未处理
        // 如果登录失效，比如session超时，user会是空指针，应该给出用户友好的提示，让用户重新登录。
        User user = userServiceImpl.getById(userServiceImpl.getIdByToken(request));
        Long uid = user.getId();
        List<Good> recommendation_goods = this.recommendGoods(pageSize, uid);

        Map<String, Object> resultMap = new HashMap<>();
        try {
            // 确保在目标查询前设置分页（中间无其他数据库操作！）
            PageHelper.startPage(page, pageSize);
            List<Good> goods = getBaseMapper().queryAllGood();
            PageInfo<Good> pageInfo = new PageInfo<>(goods);

            // 将推荐的商品和分页查询的商品
            recommendation_goods.addAll(pageInfo.getList());
            resultMap.put("products", recommendation_goods);
            resultMap.put("total", pageInfo.getTotal());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }  finally {
            PageHelper.clearPage();
        }
        return Result.ok(resultMap);
    }

    @Resource
    private JdbcTemplate jdbcTemplate;

    @Override
    public Result clickGood(Long goodId, Long userId) {
        // 验证参数
        if (goodId == null) {
            return Result.fail("商品ID不能为空");
        }
        if (userId == null) {
            return Result.fail("用户ID不能为空");
        }

        try {
            // 查询商品
            Good good = this.getById(goodId); // 假设 GoodMapper 提供 getById
            if (good == null) {
                return Result.fail("商品不存在");
            }
            Long currentPrice = good.getCurrentPrice();
            if (currentPrice == null) {
                return Result.fail("商品价格无效");
            }

            // 插入点击记录
            String insertSql = "INSERT INTO tb_good_click (good_id, current_price, user_id) VALUES (:goodId, :currentPrice, :userId)";
            // 使用 NamedParameterJdbcTemplate
            NamedParameterJdbcTemplate namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(jdbcTemplate);
            int rowsAffected = namedParameterJdbcTemplate.update(insertSql,
                    new MapSqlParameterSource()
                            .addValue("goodId", goodId)
                            .addValue("currentPrice", currentPrice)
                            .addValue("userId", userId)
            );

            if (rowsAffected > 0) {
                return Result.ok();
            } else {
                return Result.fail("插入点击记录失败");
            }
        } catch (Exception e) {
            return Result.fail("数据库操作失败: " + e.getMessage());
        }
    }
}
